<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

</body>
<script src="../underscore1.9.1.js"></script>
<script>
    // 在 underscore 中，除了 _.each 、 _.map 、 _.reduce 等函数操作集合，
    // 还提供了 _.filter 、 _.reject 、 _.every 、 _.some 这几个基于逻辑判断的集合操作函数。
    // 无一例外的是，这些函数都依赖于用户提供的 真值检测函数 用来判断当前迭代元素是否满足条件。

    // 以 _.filter 的实现为例，underscore 将真值检测函数参数命名为predicate ，十分形象。
    // 【Predicate】编程术语是断言的意思，一个返回布尔值的函数。
    //  predicate 仍然会被函数 cb 优化，如果忘记 cb函数的意图和流程，请回过头来看 underscore 基础篇 -- 迭代！迭代！迭代！


    _.filter = _.select = function(obj, predicate, context) {
        var results = [];
        predicate = cb(predicate, context);
        _.each(obj, function(value, index, list) {
            if (predicate(value, index, list)) results.push(value);
        });
        return results;
    };
    // 根据传入的元素信息，真值检测函数返回逻辑值 true 或者 false ，决定当前迭代元素是否需要被淘汰。
    // 更加方便的是，underscore 还提供了 _.negate 用来反义 predicate 的执行结果：

    _.negate = function(predicate) {
        return function() {
            return !predicate.apply(this, arguments);
        };
    };
    // 这也是一个函数层面的抽象，如果不提供 _.negate ，我们要实现与 _.filter反义的 _.reject 函数，就需要这样书写：
    _.reject = function(obj, predicate, context) {
        var results = [];
        predicate = cb(predicate, context);
        _.each(obj, function(value, index, list) {
            if (!predicate(value, index, list)) results.push(value);

        });
        return results;
    };
    // 显然，与 _.filter 有太多重复代码了。而有了 _.negate 这个抽象，实现 _.reject 我们只需要一行代码：
    _.reject = function(obj, predicate, context) {
        return _.filter(obj, _.negate(cb(predicate)), context);
    };
    // 【1】_.filter
    // _.filter(coll, predicate) ：保留 coll 中满足 predicate 的元素
    var array = [12, 50, 2, 4, 6, 13, 12];
    var lessThan10 = _.filter(array, function(elem) {
        return elem < 10;
    });
    // => lessThan10: [2,4,6]
</script>

</html>